// @ts-nocheck

export * from "./lib/clsx";
export * from "./lib/sts";
export * from "./dom-to-image.js";

export function addPx(value?: string | number): string | undefined {
	if (!value) return undefined

	value = String(value)
	return /^\d+(\.\d+)?$/.test(value) ? `${value}px` : value
}

export function containsNode(root, n) {
	if (!root) {
		return false;
	}
	return root.contains(n);
}

// camelize('font-size') => fontSize
function camelize(string) {
	return string.replace(/-(.)/g, function (_, character) {
		return character.toUpperCase();
	});
}

// underscore('getList') => get_list
export function underscore(string) {
	return string.replace(/([A-Z])/g, "_$1").toLowerCase();
}

// hyphenate('fontSize') => font-size
export function hyphenate(string) {
	return string.replace(/([A-Z])/g, "-$1").toLowerCase();
}

// merge('{0} - A front-end {1} ','Suite','framework') => Suite - A front-end framework
export function merge(pattern) {
	let pointer = 0;
	for (let i = 1; i < arguments.length; i++) {
		pattern = pattern.split("{" + pointer + "}").join(arguments[i]);
		pointer++;
	}
	return pattern;
}

// node
export function isVisible(element) {
	if (!element) {
		return false;
	}

	if (element.offsetParent) {
		return true;
	}

	if (element.getBBox) {
		const box = (element).getBBox();
		if (box.width || box.height) {
			return true;
		}
	}

	if (element.getBoundingClientRect) {
		const box = element.getBoundingClientRect();
		if (box.width || box.height) {
			return true;
		}
	}

	return false;
}

// focus
function focusable(node, includePositive = false) {
	if (isVisible(node)) {
		const nodeName = node.nodeName.toLowerCase();
		const isFocusableElement =
			// Focusable element
			["input", "select", "textarea", "button"].includes(nodeName) ||
			// Editable element
			node.isContentEditable ||
			// Anchor with href element
			(nodeName === "a" && !!node.getAttribute("href"));

		// Get tabIndex
		const tabIndexAttr = node.getAttribute("tabindex");
		const tabIndexNum = Number(tabIndexAttr);

		// Parse as number if validate
		let tabIndex = null;
		if (tabIndexAttr && !Number.isNaN(tabIndexNum)) {
			tabIndex = tabIndexNum;
		} else if (isFocusableElement && tabIndex === null) {
			tabIndex = 0;
		}

		// Block focusable if disabled
		if (isFocusableElement && node.disabled) {
			tabIndex = null;
		}

		return (
			tabIndex !== null && (tabIndex >= 0 || (includePositive && tabIndex < 0))
		);
	}

	return false;
}

export function getFocusNodeList(node, includePositive = false) {
	const res = [...node.querySelectorAll("*")].filter(child => {
		return focusable(child, includePositive);
	});
	if (focusable(node, includePositive)) {
		res.unshift(node);
	}
	return res;
}

export function limitTabRange(node, e) {
	if (e.keyCode === 9) {
		const tabNodeList = getFocusNodeList(node);
		const lastTabNode = tabNodeList[e.shiftKey ? 0 : tabNodeList.length - 1];
		const leavingTab =
			lastTabNode === document.activeElement || node === document.activeElement;

		if (leavingTab) {
			const target = tabNodeList[e.shiftKey ? tabNodeList.length - 1 : 0];
			target.focus();
			e.preventDefault();
		}
	}
}

// scroll
let cached;

export function getScrollBarSize(fresh) {
	if (typeof document === "undefined") {
		return 0;
	}

	if (fresh || cached === undefined) {
		const inner = document.createElement("div");
		inner.style.width = "100%";
		inner.style.height = "200px";

		const outer = document.createElement("div");
		const outerStyle = outer.style;

		outerStyle.position = "absolute";
		outerStyle.top = "0";
		outerStyle.left = "0";
		outerStyle.pointerEvents = "none";
		outerStyle.visibility = "hidden";
		outerStyle.width = "200px";
		outerStyle.height = "150px";
		outerStyle.overflow = "hidden";

		outer.appendChild(inner);

		document.body.appendChild(outer);

		const widthContained = inner.offsetWidth;
		outer.style.overflow = "scroll";
		let widthScroll = inner.offsetWidth;

		if (widthContained === widthScroll) {
			widthScroll = outer.clientWidth;
		}

		document.body.removeChild(outer);
		cached = widthContained - widthScroll;
	}
	return cached;
}

function _ensureSize(str) {
	const match = str.match(/^(.*)px$/);
	const value = Number(match && match[1]);
	return Number.isNaN(value) ? getScrollBarSize() : value;
}

export function getTargetScrollBarSize(target) {
	if (typeof document === "undefined" || !target || !(target instanceof Element)) {
		return {width: 0, height: 0};
	}

	const {width, height} = getStyle(target, "::-webkit-scrollbar");
	return {
		width: _ensureSize(width),
		height: _ensureSize(height)
	};
}

// support
const _animationEndEventNames = {
	WebkitAnimation: "webkitAnimationEnd",
	OAnimation: "oAnimationEnd",
	animation: "animationend"
};
const _transitionEventNames = {
	WebkitTransition: "webkitTransitionEnd",
	OTransition: "oTransitionEnd",
	transition: "transitionend"
};

function _supportEnd(names) {
	const el = document.createElement("div");
	for (const name in names) {
		if (names.hasOwnProperty(name) && el.style[name] !== undefined) {
			return {
				end: names[name]
			};
		}
	}
	return false;
}

export const canUseDOM = !!(
	typeof window !== "undefined" &&
	window.document &&
	window.document.createElement
);

export const canUseDocElement = canUseDOM && window.document.documentElement;
export const canUseAnimation = canUseDOM && _supportEnd(_animationEndEventNames);
export const canUseTransition = canUseDOM && _supportEnd(_transitionEventNames);

function _detectFlexGapSupported() {
	if (!canUseDocElement) {
		return false;
	}

	// create flex container with row-gap set
	const flex = document.createElement("div");
	flex.style.display = "flex";
	flex.style.flexDirection = "column";
	flex.style.rowGap = "1px";

	// create two, elements inside it
	flex.appendChild(document.createElement("div"));
	flex.appendChild(document.createElement("div"));

	// append to the DOM (needed to obtain scrollHeight)
	document.body.appendChild(flex);
	const flexGapSupported = flex.scrollHeight === 1; // flex container should be 1px high from the row-gap
	document.body.removeChild(flex);

	return flexGapSupported;
}

export const canUseFlexGap = _detectFlexGapSupported();

export const isStyleSupport = (styleName) => {
	if (canUseDocElement) {
		const styleNameList = Array.isArray(styleName) ? styleName : [styleName];
		const {documentElement} = window.document;

		return styleNameList.some(name => name in documentElement.style);
	}
	return false;
};

export function isEventSupported(eventNameSuffix: string, capture?: boolean): boolean {
	if (!canUseDOM || (capture && !('addEventListener' in document))) return false;

	const eventName = 'on' + eventNameSuffix;
	let isSupported: boolean = eventName in document;

	if (!isSupported) {
		const element = document.createElement('div');
		element.setAttribute(eventName, 'return;');
		isSupported = typeof element[eventName] === 'function';
	}

	if (!isSupported && eventNameSuffix === 'wheel') {
		// This is the only way to test support for the `wheel` event in IE9+.
		isSupported = document.implementation?.hasFeature?.('Events.wheel', '3.0') ?? false;
	}

	return isSupported;
}

/**
 * style
 */
const PIXEL_PATTERN = /margin|padding|width|height|max|min|offset/;

const removePixel = {
	left: true,
	top: true
};
const floatMap = {
	cssFloat: 1,
	styleFloat: 1,
	float: 1
};

function camelizeStyleName(string) {
	return camelize(string.replace(/^ms-/, "ms-"));
}

export function hyphenateStyleName(string) {
	return hyphenate(string).replace(/^ms-/, "-ms-");
}

export function getStyle(node, property) {
	if (property) {
		return node.style[camelizeStyleName(property)] || getComputedStyle(node).getPropertyValue(hyphenateStyleName(property));
	}

	return node.style || getComputedStyle(node);
}

export function removeStyle(node, keys) {
	if (typeof keys === "string") {
		return ("removeProperty" in node.style) ? node.style.removeProperty(keys) : node.style.removeAttribute(keys);
	} else if (Object.prototype.toString.call(keys) === "[object Array]") {
		keys.forEach(key => ("removeProperty" in node.style) ? node.style.removeProperty(key) : node.style.removeAttribute(key));
	}
}

export function addStyle(node, property, value) {
	if (node == null) return;
	let css = "";
	let props = property;

	if (typeof property === "string") {
		if (value === undefined) {
			new Error("value is undefined");
		}
		(props = {})[property] = value;
	}

	for (const key in props) {
		if (Object.prototype.hasOwnProperty.call(props, key)) {
			const val = props[key];
			if (val == null) {
				removeStyle(node, key);
			} else {
				css += `${key}:${props[key]};`;
			}
		}
	}

	node.style.cssText += ";" + css;
}

function _getStyleValue(node, type, value) {
	type = type.toLowerCase();
	if (value === "auto") {
		if (type === "height") {
			return node.offsetHeight;
		}
		if (type === "width") {
			return node.offsetWidth;
		}
	}
	if (!(type in removePixel)) {
		removePixel[type] = PIXEL_PATTERN.test(type);
	}
	return removePixel[type] ? (parseFloat(value) || 0) : value;
}

export function getStyleValue(node, name) {
	const length = arguments.length;
	const style = getStyle(node);

	name = floatMap[name] ? "cssFloat" in node.style ? "cssFloat" : "styleFloat" : name;

	return (length === 1) ? style : _getStyleValue(node, name, style[name] || node.style[name]);
}

export function setStyleValue(node, name, value) {
	const length = arguments.length;
	name = floatMap[name] ? "cssFloat" in node.style ? "cssFloat" : "styleFloat" : name;
	if (length === 3) {
		if (typeof value === "number" && PIXEL_PATTERN.test(name)) {
			value = `${value}px`;
		}
		node.style[name] = value; // Number
		return value;
	}
	for (const x in name) {
		if (name.hasOwnProperty(x)) {
			getStyleValue(node, x, name[x]);
		}
	}
	return getStyle(node);
}

function _getBodyContainer(option) {
	if (option.attachTo) {
		return option.attachTo;
	}

	const head = document.querySelector("head");
	return head || document.body;
}

export function injectCSS(css, option = {}) {
	if (!canUseDom()) return null;

	const styleNode = document.createElement("style");
	styleNode.nonce = option.csp && option.csp.nonce;
	styleNode.innerHTML = css;

	const container = _getBodyContainer(option);
	const {firstChild} = container;

	if (option.prepend && container.prepend) {
		// Use `prepend` first
		container.prepend(styleNode);
	} else if (option.prepend && firstChild) {
		// Fallback to `insertBefore` like IE not support `prepend`
		container.insertBefore(styleNode, firstChild);
	} else {
		container.appendChild(styleNode);
	}

	return styleNode;
}

const MARK_KEY = `rc-util-key`;
const containerCache = new Map();

export function updateCSS(css, key, option = {}) {
	const container = _getBodyContainer(option);

	// Get real parent
	if (!containerCache.has(container)) {
		const placeholderStyle = injectCSS("", option);
		const {parentNode} = placeholderStyle;
		containerCache.set(container, parentNode);
		parentNode.removeChild(placeholderStyle);
	}

	const existNode = Array.from(containerCache.get(container).children).find(
		node => node.tagName === "STYLE" && node[MARK_KEY] === key
	);

	if (existNode) {
		const cspNonce = option.csp && option.csp.nonce;
		if (cspNonce && existNode.nonce !== cspNonce) {
			existNode.nonce = cspNonce;
		}

		if (existNode.innerHTML !== css) {
			existNode.innerHTML = css;
		}

		return existNode;
	}

	const newNode = injectCSS(css, option);
	newNode[MARK_KEY] = key;
	return newNode;
}

/**
 * class
 */
export function hasClass(target, className) {
	if (target.classList) {
		return !!className && target.classList.contains(className);
	}
	return ` ${target.className} `.indexOf(` ${className} `) !== -1;
}

export function addClass(target, className) {
	if (className) {
		if (target.classList) {
			target.classList.add(className);
		} else if (!hasClass(className, target)) {
			target.className = target.className + " " + className;
		}
	}
	return target;
}

export function removeClass(target, className) {
	if (className) {
		if (target.classList) {
			target.classList.remove(className);
		} else {
			target.className = target.className
				.replace(new RegExp("(^|\\s)" + className + "(?:\\s|$)", "g"), "$1")
				.replace(/\s+/g, " ") // multiple spaces to one
				.replace(/^\s*|\s*$/g, ""); // trim the ends
		}
	}
	return target;
}

export function toggleClass(target, className) {
	if (hasClass(target, className)) {
		return removeClass(target, className);
	}
	return addClass(target, className);
}

/**
 * query
 */
export function ownerDocument(node) {
	return (node && node.ownerDocument) || document;
}

export function ownerWindow(componentOrElement) {
	const doc = ownerDocument(componentOrElement);
	return doc && doc.defaultView || doc.parentWindow;
}

export function getWindow(node) {
	return node === node.window ? node : node.nodeType === 9 ? node.defaultView || node.parentWindow : false;
}

export function getContainer(container, defaultContainer) {
	container = typeof container === "function" ? container() : container;
	return container || defaultContainer;
}

export const contains = (function () {
	const root = canUseDOM && document.documentElement;

	if (root && root.contains) {
		return (context, node) => context.contains(node);
	} else if (root && root.compareDocumentPosition) {
		return (context, node) => context === node || !!(context.compareDocumentPosition(node) & 16);
	} else {
		return (context, node) => {
			if (node) {
				do {
					if (node === context) {
						return true;
					}
				} while ((node = node.parentNode));
			}
			return false;
		};
	}
})();

export const closest = (el, selector) => {
	const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;
	while (el) {
		if (matchesSelector.call(el, selector)) {
			return el;
		}
		el = el.parentElement;
	}
	return null;
};

export function getOuterWidth(el) {
	if (el === document.body) {
		return document.documentElement.clientWidth;
	}
	return el.offsetWidth;
}

export function getOuterHeight(el) {
	if (el === document.body) {
		return window.innerHeight || document.documentElement.clientHeight;
	}
	return el.offsetHeight;
}

export function getDocSize() {
	const width = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth);
	const height = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);

	return {
		width,
		height
	};
}

export function getClientSize() {
	const width = document.documentElement.clientWidth;
	const height = window.innerHeight || document.documentElement.clientHeight;
	return {
		width,
		height
	};
}

export function getScroll() {
	return {
		scrollLeft: Math.max(document.documentElement.scrollLeft, document.body.scrollLeft),
		scrollTop: Math.max(document.documentElement.scrollTop, document.body.scrollTop)
	};
}

export function scrollTop(node, val) {
	const win = getWindow(node);
	const top = win ? (("pageYOffset" in win) ? win.pageYOffset : win.document.documentElement.scrollTop) : node.scrollTop;
	const left = win ? (("pageXOffset" in win) ? win.pageXOffset : win.document.documentElement.scrollLeft) : 0;

	if (val === undefined) {
		return top;
	}
	win ? win.scrollTo(left, val) : node.scrollTop = val;
}

export function scrollLeft(node, val) {
	const win = getWindow(node);
	const top = win ? (("pageXOffset" in win) ? win.pageXOffset : win.document.documentElement.scrollLeft) : node.scrollLeft;
	const left = win ? (("pageYOffset" in win) ? win.pageYOffset : win.document.documentElement.scrollTop) : 0;

	if (val === undefined) {
		return left;
	}

	win ? win.scrollTo(val, top) : node.scrollLeft = val;
}

export function scrollTo(element, to, duration) {
	if (duration <= 0) return;
	const difference = to - element.scrollTop;
	const perTick = difference / duration * 10;
	setTimeout(() => {
		element.scrollTop = element.scrollTop + perTick;
		if (element.scrollTop === to) return;
		scrollTo(element, to, duration - 10);
	}, 10);
}

export function getOffset(node) {
	const doc = ownerDocument(node);
	const win = getWindow(doc);
	const docElem = doc && doc.documentElement;
	let box = {
		top: 0,
		left: 0,
		height: 0,
		width: 0
	};

	if (!doc) {
		return;
	}

	// Make sure it's not a disconnected DOM node
	if (!contains(docElem, node)) {
		return box;
	}

	if (node.getBoundingClientRect !== undefined) {
		box = node.getBoundingClientRect();
	}

	if (box.width || box.height) {
		box = {
			top: box.top + (win.pageYOffset || docElem.scrollTop) - (docElem.clientTop || 0),
			left: box.left + (win.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || 0),
			width: (box.width === null ? node.offsetWidth : box.width) || 0,
			height: (box.height === null ? node.offsetHeight : box.height) || 0
		};
	}

	return box;
}

export function nodeName(node) {
	return node.nodeName && node.nodeName.toLowerCase();
}

export function getOffsetParent(node) {
	const doc = ownerDocument(node);
	let offsetParent = node && node.offsetParent;

	while (offsetParent && nodeName(node) !== "html" && getStyle(offsetParent, "position") === "static") {
		offsetParent = offsetParent.offsetParent;
	}

	return offsetParent || doc.documentElement;
}

export function getPosition(node, offsetParent) {
	const parentOffset = {
		top: 0,
		left: 0
	};

	let offset;

	// Fixed elements are offset from window (parentOffset = {top:0, left: 0},
	// because it is its only offset parent
	if (getStyle(node, "position") === "fixed") {
		offset = node.getBoundingClientRect();
	} else {
		offsetParent = offsetParent || getOffsetParent(node);
		offset = getOffset(node);

		if (nodeName(offsetParent) !== "html") {
			const nextParentOffset = getOffset(offsetParent);
			parentOffset.top = nextParentOffset.top;
			parentOffset.left = nextParentOffset.left;
		}

		parentOffset.top += (parseInt(getStyle(offsetParent, "borderTopWidth"), 10) - scrollTop(offsetParent)) || 0;
		parentOffset.left += (parseInt(getStyle(offsetParent, "borderLeftWidth"), 10) - scrollLeft(offsetParent)) || 0;
	}

	// Subtract parent offsets and node margins
	return {
		...offset,
		top: offset.top - parentOffset.top - (parseInt(getStyle(node, "marginTop"), 10) || 0),
		left: offset.left - parentOffset.left - (parseInt(getStyle(node, "marginLeft"), 10) || 0)
	};
}

export function isOverflowing(container) {
	const win = getWindow(container);
	const isBody = container && container.tagName.toLowerCase() === "body";

	function bodyIsOverflowing(node) {
		const doc = ownerDocument(node);
		const win = getWindow(doc);
		let fullWidth = win.innerWidth;

		// Support: ie8, no innerWidth
		if (!fullWidth) {
			const documentElementRect = doc.documentElement.getBoundingClientRect();
			fullWidth = documentElementRect.right - Math.abs(documentElementRect.left);
		}
		return doc.body.clientWidth < fullWidth;
	}

	return win || isBody ? bodyIsOverflowing(container) : container.scrollHeight > container.clientHeight;
}

export function getScrollbarSize(reCalc) {
	let size;
	if (!size || reCalc) {
		if (canUseDOM) {
			const scrollDiv = document.createElement("div");

			scrollDiv.style.position = "absolute";
			scrollDiv.style.top = "-9999px";
			scrollDiv.style.width = "50px";
			scrollDiv.style.height = "50px";
			scrollDiv.style.overflow = "scroll";

			document.body.appendChild(scrollDiv);
			size = scrollDiv.offsetWidth - scrollDiv.clientWidth;
			document.body.removeChild(scrollDiv);
		}
	}

	return size;
}

export function getHeight(node, client) {
	const win = getWindow(node);
	return win ? win.innerHeight : client ? node.clientHeight : getOffset(node).height;
}

export function getWidth(node, client) {
	const win = getWindow(node);
	return win ? win.innerWidth : client ? node.clientWidth : getOffset(node).width;
}

// https://www.cnblogs.com/wangkongming/p/6195903.html
// 取窗口滚动条滚动高度
export function getScrollTop() {
	var scrollTop = 0;
	if (document.documentElement && document.documentElement.scrollTop) {
		scrollTop = document.documentElement.scrollTop;
	} else if (document.body) {
		scrollTop = document.body.scrollTop;
	}
	return scrollTop;
}

// 取窗口可视范围的高度
export function getClientHeight() {
	var clientHeight = 0;
	if (document.body.clientHeight && document.documentElement.clientHeight) {
		clientHeight = (document.body.clientHeight < document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight;
	} else {
		clientHeight = (document.body.clientHeight > document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight;
	}
	return clientHeight;
}

// 取文档内容实际高度
export function getScrollHeight() {
	return Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
}

// 模块化CSS
export function setTemplateClass(pageName, templateVersion) {
	const $body = document.querySelector("body");
	$body.classList.forEach(className => {
		if (className.startsWith(pageName)) {
			$body.classList.remove(className);
		}
	});
	$body.classList.add(`${pageName}${templateVersion}`);
}

export function removeTemplateClass(pageName) {
	const $body = document.querySelector("body");
	$body.classList.forEach(className => {
		if (className.startsWith(pageName)) {
			$body.classList.remove(className);
		}
	});
}

export function scrollIntoView(container, selected) {
	if (!selected) {
		container.scrollTop = 0;
		return;
	}

	const top = selected.offsetTop;
	const bottom = selected.offsetTop + selected.offsetHeight;
	const viewRectTop = container.scrollTop;
	const viewRectBottom = viewRectTop + container.clientHeight;

	if (top < viewRectTop) {
		container.scrollTop = top;
	} else if (bottom > viewRectBottom) {
		container.scrollTop = bottom - container.clientHeight;
	}
}

export function getDeviceType() {
	const userAgent = navigator.userAgent.toLowerCase();
	const otherPhone = /(bb10|firefox os|blackberry|symbianos|palm|bada|windows mobile|ubuntu|sailfish os|samsung|meego)/i;
	let deviceType = 1; //默认手机
	if (/(android|windows phone)/i.test(userAgent)) {
		deviceType = 1;
	} else if (/(iphone)/i.test(userAgent)) {
		deviceType = 2;
	} else if (/(ipad|ipod|ios)/i.test(userAgent)) {
		deviceType = 3;
	} else if (otherPhone.test(userAgent)) {
		deviceType = 4;
	} else if (/(compatible|windows|macintosh|MacIntel)/i.test(userAgent)) {
		deviceType = 0;
	}
	return deviceType;
}

export function isMobile() {
	if (typeof navigator === "undefined" || typeof window === "undefined") {
		return false;
	}

	const agent = navigator.userAgent || navigator.vendor || window.opera;
	if (
		/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(
			agent
		) ||
		/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(
			agent && agent.substr(0, 4)
		)
	) {
		return true;
	}
	return false;
}

/**
 *
 浏览器里面，顶层对象是window
 浏览器和 Web Worker 里面，self也指向顶层对象
 Node 里面，顶层对象是global
 */
export function getGlobalThis() {
	if (typeof globalThis !== "undefined") {
		return globalThis;
	}
	if (typeof self !== "undefined") {
		return self;
	}
	if (typeof window !== "undefined") {
		return window;
	}
	if (typeof global !== "undefined") {
		return global;
	}
	throw new Error("unable to locate global object");
}

export default {
	containsNode,
	camelize,
	underscore,
	hyphenate,
	merge,
	isVisible,
	focusable,
	getFocusNodeList,
	limitTabRange,
	getScrollBarSize,
	getTargetScrollBarSize,
	canUseDocElement,
	canUseAnimation,
	canUseTransition,
	canUseFlexGap,
	camelizeStyleName,
	hyphenateStyleName,
	getStyle,
	removeStyle,
	addStyle,
	getStyleValue,
	setStyleValue,
	injectCSS,
	updateCSS,
	hasClass,
	addClass,
	removeClass,
	toggleClass,
	ownerDocument,
	ownerWindow,
	getWindow,
	getContainer,
	contains,
	closest,
	getOuterWidth,
	getOuterHeight,
	getDocSize,
	getClientSize,
	getScroll,
	scrollTop,
	scrollLeft,
	scrollTo,
	getOffset,
	nodeName,
	getPosition,
	isOverflowing,
	getScrollbarSize,
	getHeight,
	getWidth,
	getScrollTop,
	getClientHeight,
	getScrollHeight,
	setTemplateClass,
	removeTemplateClass,
	scrollIntoView,
	getDeviceType,
	isMobile,
	getGlobalThis
};
